package sistema;

import java.io.Serializable;
import java.util.*;

import dados.Usuario;

/**
 * Essa classe verifica a validade de Strings para
 * Nome, e-mail,Data e Telefone.
 * Tambem Calcula a forca de senhas.
 */
public class Verificador implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 * Verifica se o email passado eh valido, ou seja,
	 * esta no formato username@host.dominio e nao contem espacos ou
	 * caracteres invalidos : !@#$%^&*()'"<>~:;/|\?][{}
	 * @param email o e-mail a ser verificado.
	 * @return true se for valido ou false caso contrario.
	 */
	public static boolean ehEmailValido(String email){
		if (email.isEmpty()) {return false;}
		email = email.toLowerCase();
		int posicaoDoArroba = email.indexOf("@");
		if (posicaoDoArroba == -1 || posicaoDoArroba == 0 ){return false;}
		if (email.endsWith(".") || email.lastIndexOf(".") <= posicaoDoArroba +1){return false;	}
		final String CARACTERES_INVALIDOS = "!@#$%^&*()[]}{'\"<>~;:/|\\ ";
		for (int i = 0; i < posicaoDoArroba; i++){
			if (CARACTERES_INVALIDOS.indexOf(email.charAt(i)) != -1){return false;}
		}
		for (int j = posicaoDoArroba +1; j < email.lastIndexOf("."); j++){
			if (CARACTERES_INVALIDOS.indexOf(email.charAt(j)) != -1){return false;}
		}
		return true;
	}
	/**
	 * Verifica se um numero de telefone eh valido, ou seja,
	 * esta no formato (83)1234-5678.
	 * @param telefone O Telefone a ser verificado.
	 * @return true se for valido ou false caso contrario.
	 */
	public static boolean ehTelefoneValido(String telefone){
		if (telefone.length() !=13 || telefone.charAt(8)!= '-' 
				|| telefone.charAt(0)!= '(' || telefone.charAt(3)!= ')'){return false;}
		final String NUMEROS = "0987654321";
		for (int i = 0; i < telefone.length(); i++) {
			if ((i != 0 && i != 3 && i != 8) 
					&& NUMEROS.indexOf(telefone.charAt(i)) == -1 ) {return false;}
		}
		return true;
	}

	/**
	 * Verifica se uma String eh valido , ou seja, 
	 * nao eh vazia.
	 * @param nome O nome a ser verificado.
	 * @return true se for valido ,false caso o contrario.
	 */
	public static boolean ehVazio(String str){
		if(str.isEmpty()){return true;}
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i)!= ' '){return false;}
		}
		return true;
	}
	/**
	 * Verifica se eh uma data valida no formato dd/mm.
	 * Note que 29/02 eh considerada valida.
	 * @param data a data a ser verificada.
	 * @return true se for valida ou false caso contrario.
	 */
	public static boolean ehDataSemAnoValida(String data){
		if (data.length() != 5 || data.charAt(2) != '/') {return false;}
		int dia,mes;
		try{
			dia = Integer.parseInt(data.substring(0, 2));
			mes = Integer.parseInt(data.substring(3));
		}catch(NumberFormatException e){return false;}
		if (dia < 1 || dia > 31 || mes < 1 || mes > 12){return false;}
		if (mes == 2 && dia > 29){return false;}
		if ((mes==4||mes==6||mes==9||mes==11)&& dia==31){return false;}
		return true;
	}
	/**
	 * Verifica se uma data com ano eh valida,ou seja, esta em formato dd/mm/aaaa.
	 * Note que 29/02 eh valido apenas em anos bissextos.
	 * @param data A data a ser validada.
	 * @return true se for valida ou false caso contrario.
	 */
	public static boolean ehDataComAnoValida(String data){
		if(data.length()!=10 || data.charAt(5) != '/'){return false;}
		if(!ehDataSemAnoValida(data.substring(0,5))){return false;}
		int dia,mes,ano;
		try{
			dia = Integer.parseInt(data.substring(0,2));
			mes = Integer.parseInt(data.substring(3,5));
			ano = Integer.parseInt(data.substring(6));
		}catch(NumberFormatException e){return false;}
		if (ano < 1){return false;}
		if (dia == 29 && mes == 2){
			return ehAnoBissexto(ano);
		}
		return true;
	}

	private static boolean ehAnoBissexto(int ano)
	{
		if (ano%400 == 0){return true;}
		if (ano%4 == 0 && ano%100 != 0){return true;}
		return false;
	}

	/**
	 * Indica a Forca de uma Senha entre 6 e 10 caracteres.
	 * @param senha A senha a ser avaliada.
	 * @return 0 para senha Invalida; 1 para senha Fraca; 2 para senha
	 * Media ;3 para senha Forte e 4 para Muito Forte.
	 */
	public static int forcaDeSenha(String senha){
		final int TAMANHO_MINIMO = 6;
		final int TAMANHO_MAXIMO = 10;
		if (senha.length() < TAMANHO_MINIMO || senha.length()>TAMANHO_MAXIMO){return 0;}
		int forca = 0;
		final String MINUSCULAS = "abcdefghijklmnopqrstuvwxyz";
		final String MAIUSCULAS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		final String CHARS_ESPECIAIS = "!@#$%^&*`~()-_+={}][?/|\\\"' ";
		final String NUMEROS = "1234567890";
		for (int i = 0; i < senha.length(); i++) {
			if (MINUSCULAS.indexOf(senha.charAt(i)) != -1){
				forca++;
				break;
			}
		}
		for (int i = 0; i < senha.length(); i++) {
			if (MAIUSCULAS.indexOf(senha.charAt(i)) != -1){
				forca++;
				break;
			}
		}
		for (int i = 0; i < senha.length(); i++) {
			if (CHARS_ESPECIAIS.indexOf(senha.charAt(i)) != -1){
				forca++;
				break;
			}
		}
		for (int i = 0; i < senha.length(); i++) {
			if (NUMEROS.indexOf(senha.charAt(i)) != -1){
				forca++;
				break;
			}
		}
		return forca;
	}
	/**
	 * Verifica se um horario eh valido. Deve ser no formato hh:mm
	 * @param horario Horario a ser verificado
	 * @return true caso seja valido, false caso invalido
	 */
	public static boolean ehHorarioValido(String horario){
		if(horario.length() != 5){return false;}
		int hora,min;
		try{
			hora = Integer.parseInt(horario.substring(0,2));
			min = Integer.parseInt(horario.substring(3));
		}catch(NumberFormatException e){
			return false;
		}
		char divisor = horario.charAt(2);
		final String CARACTERES_INVALIDOS = "abcdefghijklmnopqrstuvxwyz!@#$%¨&*()_-=+[];.>,<*'?°ª";
		for(int i = 0; i< horario.length();i++){ 
			if( CARACTERES_INVALIDOS.indexOf(horario.charAt(i)) != -1 ) {return false;}
		}
		if(hora<0 || hora>23){return false;}
		else if(min<0 || min>=60 || divisor!=':'){return false;}
		else{return true;}
	}
	/**
	 * Verifica se o login eh possivel em uma lista de usuarios, caso seja possivel retorna o objeto Usuario
	 * @param usuarios Uma lista de usuarios
	 * @param email o login da conta
	 * @param senha a senha da conta
	 * @return O Usuario que logou
	 * @throws Exception se o e-mail for invalido, se a senha for incorreta ou o e-mail nao for encontrado
	 */
	public static Usuario autenticaLogin(List<Usuario> usuarios,String email,String senha)throws Exception{
		if (!ehEmailValido(email)){throw new Exception("E-mail Invalido.");}
		for(Usuario u: usuarios){
			if (u.getEmail().equals(email)){
				if(u.comparaSenha(senha)){
					return u;
				}
				throw new Exception("Senha Incorreta.");
			}
		}
		throw new Exception("E-mail nao cadastrado.");
	}


	/**
	 * Verifica se dentro de um array de usuarios ja existe um mesmo usuario.
	 * @param usuario
	 * @param listUsuarios
	 * @return
	 */
	public static boolean verificaUsuarioCadastrado(Usuario usuario, ArrayList<Usuario> listUsuarios){
		if(listUsuarios.contains(usuario)){
			return true;
		}
		return false;
	}
	/**
	 * Verifica se uma data qualquer é um feriado nacional
	 * @param Data String da data a ser veriicada
	 * @return True caso seja feriado, false caso nao seja feriado
	 * @throws Exception 
	 */
	public static boolean ehFeriado(String data){
		List<String> feriados = new ArrayList<String>();
		feriados.add("01/01");feriados.add("21/04");feriados.add("01/05");feriados.add("07/09");feriados.add("02/11");feriados.add("12/10");feriados.add("15/11");
		feriados.add("20/11");feriados.add("25/12");
		if(data.length()==10){
			data=data.substring(0,5);
			if(feriados.contains(data)){
				return true;
			}return false;
		}else{
			if(feriados.contains(data)){
				return true;
			}return false;
		}

	}
	/**
	 * Verifica se, dada uma data com ano, será sabado ou domingo
	 * @param data Data a ser verificada
	 * @return Retorna True caso seja fim de semana, False caso contrario.
	 */
	public static boolean ehFimDeSemana(String data){

		Calendar calendar = Calendar.getInstance();
		calendar.set(Integer.parseInt(data.substring(6)), (Integer.parseInt(data.substring(3,5))-1), Integer.parseInt(data.substring(0,2)));
		if(calendar.get(Calendar.DAY_OF_WEEK)==1 ||calendar.get(Calendar.DAY_OF_WEEK)==7){
			return true;
			}
		return false;
		

	}
}
